//
//  PopupView.swift
//  PaiPaiHappy
//
//  Created by MaiTian on 2021/7/8.
//

import UIKit

public enum AlertStyle: Int {
    // 中间弹出
    case center = 0
    // 底部弹出
    case bottom = 2
}

public protocol PopupAnimation {
    func creat(popupView: PopupView, contentView: UIView, backgroundView: PopupView.BackGroundView)
    /**
     contentView 弹框
     backgroundView 弹框背景
     completion 动画结束回调
     */
    func display(contentView: UIView, backgroundView: PopupView.BackGroundView, completion: @escaping () -> Void)
    
    func dismiss(contentView: UIView, backgroundView: PopupView.BackGroundView, completion: @escaping () -> Void)
}

public class PopupView: UIView {
    /** 将要展示回调 */
    public var willDispalyCallback: (() -> Void)?
    
    /** 已经展示回调 */
    public var didDispalyCallback: (() -> Void)?
    
    /** 将要消失回调 */
    public var willDismissCallback: (() -> Void)?
    
    /** 已经消失回调 */
    public var didDismissCallback: (() -> Void)?
    
    /** 背景 */
    public let backgroundView: BackGroundView
    
    /** 容器view */
    let containerView: UIView
    /** 内容 */
    let contentView: UIView
    
    let animator: BaseAnimation
    
    /** 是否进行动画中 */
    var isAnimating = false
    
    /** 点击背景是否消失 */
    public var isDismissible = false {
        didSet {
            backgroundView.isUserInteractionEnabled = isDismissible
        }
    }
    
    /** 创建弹框 */
    public init(containerView: UIView, contentView: UIView, animationStyle: AlertStyle = .center) {
        self.containerView = containerView
        self.contentView = contentView
        if animationStyle == .bottom {
            self.animator = BottomAnimation()
        } else {
            self.animator = CenterAnimation()
        }
        self.backgroundView = BackGroundView(frame: containerView.bounds)
        super.init(frame: containerView.bounds)
        backgroundView.isUserInteractionEnabled = isDismissible
        backgroundView.addTarget(self, action: #selector(backgroundViewClicked(sender:)), for: .touchUpInside)
        addSubview(backgroundView)
        addSubview(contentView)
        animator.creat(popupView: self, contentView: contentView, backgroundView: backgroundView)
    }
    
    /** 展示弹框 */
    public func displayPopupView(completion: (() -> Void)?) {
        if isAnimating {
            return
        }
        isAnimating = true
        containerView.addSubview(self)
        willDispalyCallback?()
        animator.display(contentView: contentView, backgroundView: backgroundView, completion: {
            completion?()
        })
        
        animator.displayAnimationBlock = { [weak self] in
            self?.isAnimating = false
            self?.didDispalyCallback?()
        }
    }

    /** 移除弹框 */
    public func dismissPopupView(completion: (() -> Void)?) {
        if isAnimating {
            return
        }
        isAnimating = true
        willDismissCallback?()
        animator.dismiss(contentView: contentView, backgroundView: backgroundView, completion: {
            completion?()
        })
        animator.dismissAnimationBlock = { [weak self] in
            self?.isAnimating = false
            self?.didDismissCallback?()
            self?.contentView.removeFromSuperview()
            self?.removeFromSuperview()
        }
    }
    
    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension PopupView {
    @objc private func backgroundViewClicked(sender: UIControl) {
        if !isAnimating {
            sender.isUserInteractionEnabled = false
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
                sender.isUserInteractionEnabled = true
            }
            dismissPopupView {}
        }
    }
    
    override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        return super.hitTest(point, with: event)
    }
}

public extension PopupView {
    class BackGroundView: UIControl {
        /** 设置背景颜色 */
        public var color = UIColor.black.withAlphaComponent(0.4) {
            didSet {
                backgroundColor = color
            }
        }
        
        @available(*, unavailable)
        required init?(coder _: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            backgroundColor = color
        }
        
        override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            let view = super.hitTest(point, with: event)
            return view
        }
    }
}

class CenterAnimation: BaseAnimation {
    override func creat(popupView: PopupView, contentView: UIView, backgroundView: PopupView.BackGroundView) {
        contentView.layoutIfNeeded()
        contentView.center = backgroundView.center
    }
    
    override func display(contentView: UIView, backgroundView: PopupView.BackGroundView, completion: @escaping () -> Void) {
        let animation = CASpringAnimation(keyPath: "transform.scale")
        animation.beginTime = 0
        // 阻尼系数（此值越大弹框效果越不明显）
        animation.damping = 22
        // 刚度系数（此值越大弹框效果越明显）
        animation.stiffness = 200
        // 质量大小（越大惯性越大）
        animation.mass = 1
        // 开始位置
        animation.fromValue = 0
        // 终止位置
        animation.toValue = 1
        // 持续时间
        animation.duration = displayDuration
        contentView.layer.add(animation, forKey: animation.keyPath)
        DispatchQueue.main.asyncAfter(deadline: .now() + displayDuration) { [weak self] in
            self?.displayAnimationBlock?()
        }
    }
    
    override func dismiss(contentView: UIView, backgroundView: PopupView.BackGroundView, completion: @escaping () -> Void) {
        UIView.animate(withDuration: dismissDuration, delay: 0, options: disMissAnimationOptions) {
            contentView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
        } completion: { [weak self] _ in
            completion()
            self?.dismissAnimationBlock?()
        }
    }
}

class BaseAnimation: PopupAnimation {
    func creat(popupView: PopupView, contentView: UIView, backgroundView: PopupView.BackGroundView) {}
    /** 展示动效 */
    func display(contentView: UIView, backgroundView: PopupView.BackGroundView, completion: @escaping () -> Void) {}
    /** 收起动效 */
    func dismiss(contentView: UIView, backgroundView: PopupView.BackGroundView, completion: @escaping () -> Void) {}
    /** 展示时长 */
    var displayDuration: TimeInterval = 0.4
    /** 展示方式 */
    var displayAnimationOptions: UIView.AnimationOptions = .curveEaseInOut
    /** 收起方式 */
    var disMissAnimationOptions: UIView.AnimationOptions = .curveLinear
    /** 收起时长 */
    var dismissDuration: TimeInterval = 0.24
    /** 展示动作 */
    var displayAnimationBlock: (() -> Void)?
    /** 收起动作 */
    var dismissAnimationBlock: (() -> Void)?
}

class BottomAnimation: BaseAnimation {
    override func creat(popupView: PopupView, contentView: UIView, backgroundView: PopupView.BackGroundView) {
        contentView.layoutIfNeeded()
        contentView.frame = CGRect(x: UIScreen.width/2 - contentView.frame.width/2, y: backgroundView.frame.height, width: contentView.frame.width, height: contentView.frame.height)
    }
    
    override func display(contentView: UIView, backgroundView: PopupView.BackGroundView, completion: @escaping () -> Void) {
        UIView.animate(withDuration: displayDuration, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 5, options: displayAnimationOptions, animations: {
            contentView.frame = CGRect(x: UIScreen.width/2 - contentView.frame.width/2, y: backgroundView.frame.height - contentView.frame.height, width: contentView.frame.width, height: contentView.frame.height)
        }) { [weak self] _ in
            completion()
            self?.displayAnimationBlock?()
        }
    }
    
    override func dismiss(contentView: UIView, backgroundView: PopupView.BackGroundView, completion: @escaping () -> Void) {
        UIView.animate(withDuration: displayDuration, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 5, options: displayAnimationOptions, animations: {
            contentView.frame = CGRect(x: UIScreen.width/2 - contentView.frame.width/2, y: backgroundView.frame.height, width: contentView.frame.width, height: contentView.frame.height)
        }) { [weak self] _ in
            completion()
            self?.dismissAnimationBlock?()
        }
    }
}

public extension UIView {
    func alertView() -> PopupView? {
        if superview?.isKind(of: PopupView.self) == true {
            return superview as? PopupView
        }
        return nil
    }
}
